package com.apex.lottery.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.apex.lottery.common.errorcode.ServiceErrorCodeConstants;
import com.apex.lottery.common.exception.ServiceException;
import com.apex.lottery.common.utils.JWTUtil;
import com.apex.lottery.common.utils.RegexUtil;
import com.apex.lottery.controller.param.ShortMessageLoginParam;
import com.apex.lottery.controller.param.UserLoginParam;
import com.apex.lottery.controller.param.UserPasswordLoginParam;
import com.apex.lottery.controller.param.UserRegisterParam;
import com.apex.lottery.dao.dataobject.Encrypt;
import com.apex.lottery.dao.dataobject.UserDO;
import com.apex.lottery.dao.mapper.UserMapper;
import com.apex.lottery.service.UserService;
import com.apex.lottery.service.VerificationCodeService;
import com.apex.lottery.service.dto.UserDTO;
import com.apex.lottery.service.dto.UserLoginDTO;
import com.apex.lottery.service.dto.UserServiceDTO;
import com.apex.lottery.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName UserServiceImpl
 * @Description 实现类
 * @Author ZJX
 * @Date 2024/9/23 16:09
 * @Version 1.0
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private VerificationCodeService verificationCodeService;

    @Override
    public UserServiceDTO register(UserRegisterParam param) {

//        校验注册信息
        checkRegisterInfo(param);

//        加密隐私数据(构造dao层请求)
        UserDO userDO = new UserDO();
        userDO.setUserName(param.getName());
        userDO.setEmail(param.getMail());
        userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));
        userDO.setIdentity(param.getIdentity());
        if (StringUtils.hasText(param.getPassword())) {
            userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));
        }

//        保存数据
        userMapper.insert(userDO);


//        构造返回
        UserServiceDTO userServiceDTO = new UserServiceDTO();
        userServiceDTO.setUserId(userDO.getId());
        return userServiceDTO;
    }

    @Override
    public UserLoginDTO login(UserLoginParam param) {
        UserLoginDTO userLoginDTO;

        // 类型检查与类型转换，java 14及以上版本
        if (param instanceof UserPasswordLoginParam loginParam) {
            // 密码登录流程
            userLoginDTO = loginByUserPassword(loginParam);
        } else if (param instanceof ShortMessageLoginParam loginParam) {
            // 短信验证码登录流程
            userLoginDTO = loginByShortMessage(loginParam);
        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);
        }

        return userLoginDTO;
    }

    /**
     * 查询用户信息
     *
     * @param identity
     * @return
     */
    @Override
    public List<UserDTO> findUserInfo(UserIdentityEnum identity) {
        String result = identity == null ? null : identity.name();
        List<UserDO> userDOList = userMapper.selectUserListByIdentity(result);

        List<UserDTO> userDTOList = userDOList.stream().map(userDO -> {
            UserDTO userDTO = new UserDTO();
            userDTO.setUserId(userDO.getId());
            userDTO.setUserName(userDO.getUserName());
            userDTO.setEmail(userDO.getEmail());
            userDTO.setPhoneNumber(userDO.getPhoneNumber().getValue());
            userDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
            return userDTO;
        }).toList();

        return userDTOList;
    }

    /**
     * 验证码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {
        if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

        // 获取用户数据
        UserDO userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));

        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);
        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity())
                && !loginParam.getMandatoryIdentity()
                .equalsIgnoreCase(userDO.getIdentity())) {
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

        // 校验验证码
        String code = verificationCodeService.getVerificationCode(loginParam.getLoginMobile());
        if (!loginParam.getVerificationCode().equals(code)) {
            throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);
        }

        // 塞入返回值（JWT）
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;


    }

    /**
     * 密码登录
     *
     * @param loginParam
     * @return
     */
    private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {

        UserDO userDO = null;
        // 判断手机登录还是邮箱登录
        if (RegexUtil.checkMail(loginParam.getLoginName())) {
            // 邮箱登录
            // 根据邮箱查询用户表
            userDO = userMapper.selectByMail(loginParam.getLoginName());
        } else if (RegexUtil.checkMobile(loginParam.getLoginName())) {
            // 手机号登录
            // 根据手机号查询用户表
            userDO = userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));
        } else {
            throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);
        }

        // 校验登录信息
        if (null == userDO) {
            throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);

        } else if (StringUtils.hasText(loginParam.getMandatoryIdentity()) && !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {
            // 强制身份登录，身份校验不通过
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);

        } else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {
            // 校验密码不同
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }

        // 塞入返回值（JWT）
        Map<String, Object> claim = new HashMap<>();
        claim.put("id", userDO.getId());
        claim.put("identity", userDO.getIdentity());
        String token = JWTUtil.genJwt(claim);

        UserLoginDTO userLoginDTO = new UserLoginDTO();
        userLoginDTO.setToken(token);
        userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));
        return userLoginDTO;

    }



    private void checkRegisterInfo(UserRegisterParam param) {
        if (param == null){
            throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }

//        校验邮箱格式  XXX@XXX.XXX
        if(!RegexUtil.checkMail(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);
        }

//        校验手机号格式
        if (!RegexUtil.checkMobile(param.getPhoneNumber())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);
        }

//        校验身份信息
        if (UserIdentityEnum.forName(param.getIdentity()) == null){
            throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);
        }

//        校验 管理员密码必填
        if (param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name()) && !StringUtils.hasText(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }

//        密码检验 至少六位
        if (StringUtils.hasText(param.getPassword())
                && RegexUtil.checkPassword(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }


//        确保手机号跟邮箱是唯一的
        if (checkMailUsed(param.getMail())){
            throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);
        }

//        由于手机号属于私密信息 所以 手机号要先加密再进行检验
        if (checkPasswordUsed(param.getPassword())){
            throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);
        }

    }

    private boolean checkMailUsed(String mail) {
        return userMapper.countByMail(mail) > 0;
    }

    private boolean checkPasswordUsed(String password) {
        return userMapper.countByPhone(new Encrypt(password)) > 0;
    }
}
